#include "stdafx.h"
#include "App.h"

App * gApp = 0;
IDirect3DDevice9 * gD3D = 0;

LRESULT CALLBACK
MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	// Don't start processing messages until the application has been created.
	if( gApp != 0 )
		return gApp->WndProc(hwnd, msg, wParam, lParam);
	else
		return DefWindowProc(hwnd, msg, wParam, lParam);
}

App::App(HINSTANCE hInst) : xPos(100), yPos(100), width(800), height(800), paused(false)
{
	this->hInst = hInst;

	gApp = this;

	style = WS_OVERLAPPEDWINDOW;
	strcpy_s(className, "FooBar");
	strcpy_s(frameCaption, "FooBar");
}

App::~App(void)
{
	UnregisterClass(className, hInst);
}



bool App::Run()
{

	ZeroMemory(&wndClassEX, sizeof(WNDCLASSEX));

	wndClassEX.cbSize = sizeof(wndClassEX);
	wndClassEX.style = CS_HREDRAW | CS_VREDRAW;
	wndClassEX.lpfnWndProc = MainWndProc;
	wndClassEX.cbClsExtra = 0;
	wndClassEX.cbWndExtra = 0;
	wndClassEX.hInstance = hInst;
	wndClassEX.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClassEX.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClassEX.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);	
	wndClassEX.lpszClassName = className;
	wndClassEX.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	
	if(RegisterClassEx(&wndClassEX) == false)
	{
		AppError(true, "Failed to register Window");
		return false;
	}

	RECT client;
	SetRect(&client, 0, 0, width, height);
	AdjustWindowRect(&client, style, FALSE);

	width = client.right - client.left;
	height = client.bottom - client.top;
	hWND = CreateWindow(className, //class name
		frameCaption,			   //window title
		style,                     //window style
		0, 0,                      //x, y coordinates
		width, height,             //height and width of window
		NULL, NULL,                //parent window and menu
		hInst,                     //handle to application instance
		NULL);        

	if(hWND == NULL)
	{
		AppError(true, "Could not create Window");
		return false;
	}

	ShowWindow(hWND, SW_NORMAL);
	UpdateWindow(hWND);

	Init();

	MSG  msg;
	msg.message = WM_NULL;

	//timer
	__int64 cntsPerSec = 0;
	QueryPerformanceFrequency((LARGE_INTEGER*)&cntsPerSec);
	float secsPerCnt = 1.0f / (float)cntsPerSec;

	__int64 prevTimeStamp = 0;
	QueryPerformanceCounter((LARGE_INTEGER*)&prevTimeStamp);

	while(msg.message != WM_QUIT)
	{
		// If there are Window messages then process them.
		if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
		// Otherwise, do animation/game stuff.
		else
		{	
			// If the application is paused then free some CPU cycles to other 
			// applications and then continue on to the next frame.
			if( paused )
			{
				Sleep(20);
				continue;
			}
			
			if(gGraphics->IsDeviceLost() == false)
			{
				__int64 currTimeStamp = 0;
				QueryPerformanceCounter((LARGE_INTEGER*)&currTimeStamp);
				float dt = (currTimeStamp - prevTimeStamp)*secsPerCnt;

				gGraphics->Update(dt);
				Frame();
				
				prevTimeStamp = currTimeStamp;
			}
		}
	}

	Shutdown();

	return true;
}


void App::AppError(BOOL Fatal, char * text, ...)
{
	char captionText[12];
	char errorText[2048];

	va_list valist;

	if(Fatal)
		strcpy_s(captionText, "Fatal Error");
	else
		strcpy_s(captionText, "Error");

	va_start(valist, text);
	vsprintf_s(errorText, text, valist);
	va_end(valist);

	MessageBox(NULL, errorText, captionText, MB_OK | MB_ICONEXCLAMATION);

	if(Fatal)
		PostQuitMessage(0);	


}

LRESULT App::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ 
	// Is the application in a minimized or maximized state?
	static bool minOrMaxed = false;

	RECT clientRect = {0, 0, 0, 0};
	switch( msg )
	{

		// WM_ACTIVE is sent when the window is activated or deactivated.
		// We pause the game when the main window is deactivated and 
		// unpause it when it becomes active.
	case WM_ACTIVATE:
		if( LOWORD(wParam) == WA_INACTIVE )
		{
			COUT("Paused");
			paused = true;
		}
		else
		{

			COUT("Unpaused");

			paused = false;
		}
		return 0;


		// WM_SIZE is sent when the user resizes the window.  
	//case WM_SIZE:
	//	if( gD3D)
	//	{
	//		gGraphics->SetBackBufferWidth(LOWORD(lParam));
	//		gGraphics->SetBackBufferHeight(HIWORD(lParam));

	//		if( wParam == SIZE_MINIMIZED )
	//		{
	//			paused = true;
	//			minOrMaxed = true;
	//		}
	//		else if( wParam == SIZE_MAXIMIZED )
	//		{
	//			paused = false;
	//			minOrMaxed = true;
	//			gGraphics->OnLostDevice();
	//			
	//			gGraphics->OnResetDevice();
	//		}
	//		// Restored is any resize that is not a minimize or maximize.
	//		// For example, restoring the window to its default size
	//		// after a minimize or maximize, or from dragging the resize
	//		// bars.
	//		else if( wParam == SIZE_RESTORED )
	//		{
	//			paused = false;

	//			// Are we restoring from a mimimized or maximized state, 
	//			// and are in windowed mode?  Do not execute this code if 
	//			// we are restoring to full screen mode.
	//			if( minOrMaxed && gGraphics->Windowed())
	//			{
	//				gGraphics->OnLostDevice();
	//				gGraphics->OnResetDevice();
	//			}
	//			else
	//			{
	//				// No, which implies the user is resizing by dragging
	//				// the resize bars.  However, we do not reset the device
	//				// here because as the user continuously drags the resize
	//				// bars, a stream of WM_SIZE messages is sent to the window,
	//				// and it would be pointless (and slow) to reset for each
	//				// WM_SIZE message received from dragging the resize bars.
	//				// So instead, we reset after the user is done resizing the
	//				// window and releases the resize bars, which sends a
	//				// WM_EXITSIZEMOVE message.
	//			}
	//			minOrMaxed = false;
	//		}
	//	}
	//	return 0;


		// WM_EXITSIZEMOVE is sent when the user releases the resize bars.
		// Here we reset everything based on the new window dimensions.
	//case WM_EXITSIZEMOVE:
	//	GetClientRect(hWnd, &clientRect);
	//	if(gGraphics != NULL)
	//		gGraphics->Resize(clientRect);
	//	return 0;
	//	// WM_CLOSE is sent when the user presses the 'X' button in the
	//	// caption bar menu.
	case WM_CLOSE:
		DestroyWindow(hWnd);
		return 0;

		// WM_DESTROY is sent when the window is being destroyed.
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam); 
}